package com.ficus.road.maintain.core.infrastructure.mongo.converter;

import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;

public class EnumConverterFactory implements ConverterFactory<Integer, Enum> {
    /**
     * 根据Enum的类型生成需要的 Int to Enum Converter
     *
     * @param targetType 目标Enum类型class对象
     * @param <T>        目标Enum类型
     * @return 生成的Converter
     */
    @Override
    public <T extends Enum> Converter<Integer, T> getConverter(Class<T> targetType) {
        Class<?> enumType = targetType;
        while (enumType != null && !enumType.isEnum()) {
            enumType = enumType.getSuperclass();
        }
        if (enumType == null) {
            throw new IllegalArgumentException(
                    "The target type " + targetType.toString() + " does not refer to an enum");
        }
        // todo 这句ide在提示什么,找个大师学学反射
        return new IntegerToEnumConverter(enumType);
    }

    /**
     * Int 转 Enum
     * <p>
     * 根据Enum的类型决定怎么转化
     *
     * @param <T> Enum的类型
     */
    @ReadingConverter
    public static class IntegerToEnumConverter<T extends Enum> implements Converter<Integer, Enum> {
        private final Class<T> enumType;

        public IntegerToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        @Override
        public Enum convert(Integer source) {
            for (T t : enumType.getEnumConstants()) {
                if (t instanceof IntEnum) {
                    if (((IntEnum) t).getCode() == source) {
                        return t;
                    }
                }
            }
            return null;
        }
    }

    /**
     * Enum to Int
     * <p>
     * 为实现了{@link IntEnum}的Enum提供转Int功能
     */
    @WritingConverter
    public static class EnumToIntegerConverter implements Converter<Enum<?>, Object> {
        @Override
        public Object convert(Enum<?> source) {
            if (source instanceof IntEnum) {
                return ((IntEnum) (source)).getCode();
            } else {
                return source.name();
            }
        }
    }
}